#!/usr/bin/env python3

# Copyright (c) 2020-2021 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


from .._const import Arch, Lang
from .._vm import VmConfig


class Spec:

    _timeZoneDict = {
        "000": ("Dateline Standard Time",                                  "(GMT-12:00) International Date Line West"),
        "001": ("Samoa Standard Time",                                     "(GMT-11:00) Midway Island, Samoa"),
        "002": ("Hawaiian Standard Time",                                  "(GMT-10:00) Hawaii"),
        "003": ("Alaskan Standard Time",                                   "(GMT-09:00) Alaska"),
        "004": ("Pacific Standard Time",                                   "(GMT-08:00) Pacific Time (US and Canada); Tijuana"),
        "010": ("Mountain Standard Time",                                  "(GMT-07:00) Mountain Time (US and Canada)"),
        "013": ("Mexico Standard Time 2",                                  "(GMT-07:00) Chihuahua, La Paz, Mazatlan"),
        "015": ("U.S. Mountain Standard Time",                             "(GMT-07:00) Arizona"),
        "020": ("Central Standard Time",                                   "(GMT-06:00) Central Time (US and Canada)"),
        "025": ("Canada Central Standard Time",                            "(GMT-06:00) Saskatchewan"),
        "030": ("Mexico Standard Time",                                    "(GMT-06:00) Guadalajara, Mexico City, Monterrey"),
        "033": ("Central America Standard Time",                           "(GMT-06:00) Central America"),
        "035": ("Eastern Standard Time",                                   "(GMT-05:00) Eastern Time (US and Canada)"),
        "040": ("U.S. Eastern Standard Time",                              "(GMT-05:00) Indiana (East)"),
        "045": ("S.A. Pacific Standard Time",                              "(GMT-05:00) Bogota, Lima, Quito"),
        "050": ("Atlantic Standard Time",                                  "(GMT-04:00) Atlantic Time (Canada)"),
        "055": ("S.A. Western Standard Time",                              "(GMT-04:00) Caracas, La Paz"),
        "056": ("Pacific S.A. Standard Time",                              "(GMT-04:00) Santiago"),
        "060": ("Newfoundland and Labrador Standard Time",                 "(GMT-03:30) Newfoundland and Labrador"),
        "065": ("E. South America Standard Time",                          "(GMT-03:00) Brasilia"),
        "070": ("S.A. Eastern Standard Time",                              "(GMT-03:00) Buenos Aires, Georgetown"),
        "073": ("Greenland Standard Time",                                 "(GMT-03:00) Greenland"),
        "075": ("Mid-Atlantic Standard Time",                              "(GMT-02:00) Mid-Atlantic"),
        "080": ("Azores Standard Time",                                    "(GMT-01:00) Azores"),
        "083": ("Cape Verde Standard Time",                                "(GMT-01:00) Cape Verde Islands"),
        "085": ("GMT Standard Time",                                       "(GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London"),
        "090": ("Greenwich Standard Time",                                 "(GMT) Casablanca, Monrovia"),
        "095": ("Central Europe Standard Time",                            "(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague"),
        "100": ("Central European Standard Time",                          "(GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb"),
        "105": ("Romance Standard Time",                                   "(GMT+01:00) Brussels, Copenhagen, Madrid, Paris"),
        "110": ("W. Europe Standard Time",                                 "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"),
        "113": ("W. Central Africa Standard Time",                         "(GMT+01:00) West Central Africa"),
        "115": ("E. Europe Standard Time",                                 "(GMT+02:00) Bucharest"),
        "120": ("Egypt Standard Time",                                     "(GMT+02:00) Cairo"),
        "125": ("FLE Standard Time",                                       "(GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius"),
        "130": ("GTB Standard Time",                                       "(GMT+02:00) Athens, Istanbul, Minsk"),
        "135": ("Israel Standard Time",                                    "(GMT+02:00) Jerusalem"),
        "140": ("South Africa Standard Time",                              "(GMT+02:00) Harare, Pretoria"),
        "145": ("Russian Standard Time",                                   "(GMT+03:00) Moscow, St. Petersburg, Volgograd"),
        "150": ("Arab Standard Time",                                      "(GMT+03:00) Kuwait, Riyadh"),
        "155": ("E. Africa Standard Time",                                 "(GMT+03:00) Nairobi"),
        "158": ("Arabic Standard Time",                                    "(GMT+03:00) Baghdad"),
        "160": ("Iran Standard Time",                                      "(GMT+03:30) Tehran"),
        "165": ("Arabian Standard Time",                                   "(GMT+04:00) Abu Dhabi, Muscat"),
        "170": ("Caucasus Standard Time",                                  "(GMT+04:00) Baku, Tbilisi, Yerevan"),
        "175": ("Transitional Islamic State of Afghanistan Standard Time", "(GMT+04:30) Kabul"),
        "180": ("Ekaterinburg Standard Time",                              "(GMT+05:00) Ekaterinburg"),
        "185": ("West Asia Standard Time",                                 "(GMT+05:00) Islamabad, Karachi, Tashkent"),
        "190": ("India Standard Time",                                     "(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi"),
        "193": ("Nepal Standard Time",                                     "(GMT+05:45) Kathmandu"),
        "195": ("Central Asia Standard Time",                              "(GMT+06:00) Astana, Dhaka"),
        "200": ("Sri Lanka Standard Time",                                 "(GMT+06:00) Sri Jayawardenepura"),
        "201": ("N. Central Asia Standard Time",                           "(GMT+06:00) Almaty, Novosibirsk"),
        "203": ("Myanmar Standard Time",                                   "(GMT+06:30) Yangon (Rangoon)"),
        "205": ("S.E. Asia Standard Time",                                 "(GMT+07:00) Bangkok, Hanoi, Jakarta"),
        "207": ("North Asia Standard Time",                                "(GMT+07:00) Krasnoyarsk"),
        "210": ("China Standard Time",                                     "(GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi"),
        "215": ("Singapore Standard Time",                                 "(GMT+08:00) Kuala Lumpur, Singapore"),
        "220": ("Taipei Standard Time",                                    "(GMT+08:00) Taipei"),
        "225": ("W. Australia Standard Time",                              "(GMT+08:00) Perth"),
        "227": ("North Asia East Standard Time",                           "(GMT+08:00) Irkutsk, Ulan Bator"),
        "230": ("Korea Standard Time",                                     "(GMT+09:00) Seoul"),
        "235": ("Tokyo Standard Time",                                     "(GMT+09:00) Osaka, Sapporo, Tokyo"),
        "240": ("Yakutsk Standard Time",                                   "(GMT+09:00) Yakutsk"),
        "245": ("A.U.S. Central Standard Time",                            "(GMT+09:30) Darwin"),
        "250": ("Cen. Australia Standard Time",                            "(GMT+09:30) Adelaide"),
        "255": ("A.U.S. Eastern Standard Time",                            "(GMT+10:00) Canberra, Melbourne, Sydney"),
        "260": ("E. Australia Standard Time",                              "(GMT+10:00) Brisbane"),
        "265": ("Tasmania Standard Time",                                  "(GMT+10:00) Hobart"),
        "270": ("Vladivostok Standard Time",                               "(GMT+10:00) Vladivostok"),
        "275": ("West Pacific Standard Time",                              "(GMT+10:00) Guam, Port Moresby"),
        "280": ("Central Pacific Standard Time",                           "(GMT+11:00) Magadan, Solomon Islands, New Caledonia"),
        "285": ("Fiji Islands Standard Time",                              "(GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands"),
        "290": ("New Zealand Standard Time",                               "(GMT+12:00) Auckland, Wellington"),
        "300": ("Tonga Standard Time",                                     "(GMT+13:00) Nuku'alofa"),
    }

    # this is from [Keyboard Layout] section in TXTSETUP.INI in windows XP installation ISO
    # FIXME: does every edition has the same content?
    _keyboardLayoutDict = {
        "0000041C": "Albanian",
        "00000423": "Belarusian",
        "00000813": "Belgian Dutch",
        "0000080C": "Belgian French",
        "00000416": "Brazilian (ABNT)",
        "00000402": "Bulgarian",
        "00010402": "Bulgarian Latin",
        "00001009": "Canadian English (Multilingual)",
        "00000C0C": "Canadian French",
        "00010C0C": "Canadian French (Multilingual)",
        "0000041a": "Croatian",
        "00000405": "Czech",
        "00010405": "Czech (QWERTY)",
        "00000406": "Danish",
        "00000413": "Dutch",
        "00000425": "Estonian",
        "0000040B": "Finnish",
        "0000040C": "French",
        "00000407": "German",
        "00010407": "German (IBM)",
        "00000408": "Greek",
        "00050408": "Greek Latin",
        "00010408": "Greek (220)",
        "00030408": "Greek (220) Latin",
        "00020408": "Greek (319)",
        "00040408": "Greek (319) Latin",
        "0000040E": "Hungarian",
        "0001040E": "Hungarian 101-key",
        "0000040F": "Icelandic",
        "00001809": "Irish",
        "00000410": "Italian",
        "00010410": "Italian (142)",
        "0000080A": "Latin American",
        "00000426": "Latvian",
        "00010426": "Latvian (QWERTY)",
        "00000427": "Lithuanian",
        "00000414": "Norwegian",
        "00000415": "Polish (Programmers)",
        "00010415": "Polish (214)",
        "00000816": "Portuguese",
        "00000418": "Romanian",
        "00000419": "Russian",
        "00010419": "Russian (Typewriter)",
        "00000C1A": "Serbian Cyrillic",
        "00010C1A": "Serbian Latin",
        "0000041B": "Slovak",
        "0001041B": "Slovak (QWERTY)",
        "00000424": "Slovenian",
        "0000040A": "Spanish",
        "0001040A": "Spanish variation",
        "0000041D": "Swedish",
        "0000100C": "Swiss French",
        "00000807": "Swiss German",
        "0001041F": "Turkish F",
        "0000041F": "Turkish Q",
        "00000422": "Ukrainian",
        "00000809": "United Kingdom",
        "00000409": "US",
        "00010409": "US-Dvorak",
        "00030409": "US-Dvorak for left hand",
        "00040409": "US-Dvorak for right hand",
        "00020409": "US-International",
    }

    _langGroupDict = {
        Lang.en_US: "10",
        Lang.zh_CN: "10",
        Lang.zh_TW: "10",
    }

    # from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid
    _langDict = {
        Lang.en_US: "00000804",
        Lang.zh_CN: "00000804",
        Lang.zh_TW: "00000804",
    }

    def __init__(self, arch):
        assert isinstance(arch, Arch)
        self._arch = arch

    def getTimeZoneIndexList(self):
        return list(self._timeZoneDict.keys())

    def getKeyboardLayoutList(self):
        return list(self._keyboardLayoutDict.values())

    def getKeyboardLayoutValue(self, keyboardLayout):
        for k, v in self._keyboardLayoutDict.items():
            if v == keyboardLayout:
                return k
        assert False

    def getKeyboardLayoutByLang(self, lang):
        # FIXME
        return ""

    def getLocaleList(self):
        return [""]

    def getLocationByLang(self, lang):
        # FIXME
        return ""

    def getLanguageGroupList(self):
        return ["10"]

    def getLanguageGroupCodeByLang(self, lang):
        return self._langGroupDict[lang]

    def getLanguageIdList(self):
        return ["00000804"]

    def getLanguageIdByLang(self, lang):
        return self._langDict[lang]

    def getTimezoneCodeByLang(self, lang):
        if lang == Lang.en_US:
            return "085"
        elif lang == Lang.zh_CN:
            return "085"
        elif lang == Lang.zh_TW:
            return "085"
        else:
            assert False

    def getMainDiskSize(self):
        return "10G"

    def getStorageLayoutName(self):
        return "bios-ntfs"

    def getVmConfig(self):
        if self._arch == Arch.X86:
            return VmConfig(qemu_vm_type="pc",
                            cpu_arch="x86",
                            cpu_number=1,
                            memory_size="1G",
                            bios_type="bios",
                            disk_interface="ide",
                            network_type="none")
        elif self._arch == Arch.X86_64:
            return VmConfig(qemu_vm_type="pc",
                            cpu_arch="amd64",
                            cpu_number=1,
                            memory_size="1G",
                            bios_type="bios",
                            disk_interface="ide",
                            network_type="none")
        else:
            assert False

    def getDefaultScreenSaverTimeout(self):
        return 60 * 15              # default timeout is 5 minutes
